package com.qsxc.system.aspect;

import com.alibaba.fastjson.JSONObject;
import com.qsxc.business.bean.R;
import com.qsxc.system.annotation.SysLog;
import com.qsxc.system.log.LogUtil;
import com.qsxc.utils.StringUtil;
import com.qsxc.utils.WebUtil;
import org.apache.http.protocol.HTTP;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 系统日志，切面处理类
 *
 * @author chenhongwei
 */
@Aspect
@Component
@Order
public class LogAspect {
    @Value("${spring.profiles.active}")
    private String active;

    @Pointcut("@annotation(com.qsxc.system.annotation.SysLog)")
    public void pointCut() {
    }

    @Around("pointCut() && @annotation(sysLog)")
    public Object around(ProceedingJoinPoint joinPoint, SysLog sysLog) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String logInfo = "";
        if (sysLog != null) {
            //注解上的描述
            logInfo = sysLog.value();
        }
        //请求的方法名
        String methodName = signature.getName();

        //请求的参数
        Object result = null;
        try {
            //前置通知
            HttpServletRequest request = WebUtil.getRequest();
            //2.获得所有头的名称
            Map<String, Object> headersParamMap = new HashMap<>();
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {//判断是否还有下一个元素
                String nextElement = headerNames.nextElement();//获取headerNames集合中的请求头
                String header2 = request.getHeader(nextElement);//通过请求头得到请求内容
                headersParamMap.put(nextElement, header2);
            }
            Map<?, ?> inputParamMap = null;
            Object[] args = joinPoint.getArgs();
            String userId = null;
            //3.获取请求参数集合并进行遍历拼接
            if (args.length > 0) {
                if ("POST".equals(request.getMethod())) {
                    inputParamMap = getKeyAndValue(args[0]);
                } else if ("GET".equals(request.getMethod())) {
                    inputParamMap = request.getParameterMap();
                }
            }

            if (sysLog != null && sysLog.enabled()) {
                //设置IP地址
                String ip = WebUtil.getIP(request);
                LogUtil.init();
                if ("prod".equals(active)) {
                    String param = JSONObject.toJSONString(inputParamMap);
                    if (param.length() > 1000) {
                        param = param.substring(0, 1000) + "...";
                    }
                    if (StringUtil.isEmpty(param)) {
                        LogUtil.info(String.format("【%s-请求】:%s ", logInfo, request.getRequestURI()));
                    } else {
                        LogUtil.info(String.format("【%s-请求】:%s 【params】：%s", logInfo, request.getRequestURI(), param));
                    }
                } else {
                    LogUtil.info(String.format("【%s-请求】:%s 【IP】：%s \n【headers】：%s \n【params】：%s", logInfo,
                            request.getRequestURI(), ip, JSONObject.toJSONString(headersParamMap), JSONObject.toJSONString(inputParamMap)));
                }
            }
            //执行目标方法
            result = joinPoint.proceed();
            if (sysLog != null && sysLog.enabled()) {
                R r = (R) result;
                if (sysLog.ignoreData()) {
                    LogUtil.info(String.format("【%s-返回】：%s", logInfo, r.getMsg()));
                } else {
                    LogUtil.info(String.format("【%s-返回】：%s", logInfo, JSONObject.toJSONString(r)));
                }
            }
        } catch (Throwable e) {
            throw e;
        }
        LogUtil.printAll();
        return result;
    }

    private Map<String, Object> getKeyAndValue(Object obj) {
        Map<String, Object> map = new HashMap<>();
        if (obj == null) {
            return map;
        }
        // 得到类对象
        Class userCla = obj.getClass();
        /* 得到类中的所有属性集合 */
        Field[] fs = userCla.getDeclaredFields();
        for (Field f : fs) {
            f.setAccessible(true); // 设置些属性是可以访问的
            Object val;
            try {
                val = f.get(obj);
                // 得到此属性的值
                map.put(f.getName(), val);// 设置键值
            } catch (IllegalArgumentException | IllegalAccessException e) {
            }
        }
        return map;
    }

    private void testJsonStringify(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(request.getInputStream()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        String line = null;
        StringBuilder sb = new StringBuilder();
        try {
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        String reqBody = sb.toString();
        String jString = null;
        try {
            jString = URLDecoder.decode(reqBody, HTTP.UTF_8);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println(jString);
    }
}
